var map;
var boatPointSource = new ol.source.Vector({
    wrapX: false //禁止水平环绕
});
var boatIconChangedZoom = 6;
var selectedBoatFeature;
var mapDpi = 96;//超图默认
var mapUnit = "DEGREE";//超图默认
var mapProjection = "EPSG:4326";
var motherMapUrl = "https://iserver.supermap.io/iserver/services/map-world/rest/maps/World";
var baseChartUrl = mapHost;
var sourceUrlList = [motherMapUrl, baseChartUrl];
//世界地图的范围
var bounds = {
    "top": 85.05112877980648,
    "left": -180,
    "bottom": -85.0511287798065,
    "leftBottom": {
        "x": -180,
        "y": -85.0511287798065
    },
    "right": 180,
    "rightTop": {
        "x": 180,
        "y": 85.05112877980648
    }
};
var zoomLevel = 4;
//当前瓦片图的比例尺，后续如果再细化可以继续添加
var visualScale = [1 / 64000000, 1 / 32000000, 1 / 16000000, 1 / 8000000, 1 / 4000000, 1 / 2000000,
    1 / 1000000, 1 / 500000, 1 / 250000, 1 / 125000, 1 / 64000, 1 / 32000, 1 / 16000];
var visualResolution = [];
calculateResolutions(visualScale, visualResolution);


//测距用
var measureSource;
var measureDraw;

function boatMoveListener(e) {
    var select = false;
    map.forEachFeatureAtPixel(e.pixel, function (feature) {
        if (feature.getProperties().type === featureType.boat && !mapMove) {
            var pixel = map.getPixelFromCoordinate([feature.getProperties().lng, feature.getProperties().lat]);
            mapMarkHoverIn(feature.getProperties().code, pixel[1] + 20, pixel[0] + 20);
            select = true
            return true;
        }
    }, {
        hitTolerance: 20
    });
    if (!select) {
        mapMarkHoverOut();
    }
}

var mapMove = false;

function mapMoveStartListener(e) {
    mapMove = true;
    hideBoatInfo();
}

function mapMoveEndListener(e) {
    mapMove = false;
}

function resolutionChangeListener(e) {
    var zoom = map.getView().getZoom();
    if ((zoomLevel <= boatIconChangedZoom && zoom > boatIconChangedZoom) ||
        (zoomLevel > boatIconChangedZoom && zoom <= boatIconChangedZoom)) {
        //大于 4 boat用 带指向的三角符号标识
        //小于 4 boat用 圆点标识
        changeBoatFeatureStyle(zoom);
    }
    zoomLevel = zoom;
}

function singleClickListener(e) {
    map.forEachFeatureAtPixel(e.pixel, function (feature) {
            if (feature.getProperties().type === featureType.boat) {
                hideBoatInfo();
                mapMarkerClick(feature.getProperties().code);
                return true;//结束循环 不然 如果两条boat靠的很近会触发两次
            }
        }, {hitTolerance: 0}
    );
}

function calculateResolutions(scaleArray, resolutionArray) {
    for (let i = 0; i < scaleArray.length; i++) {
        resolutionArray[i] = scaleToResolution(scaleArray[i], mapDpi, mapUnit);
    }
}

async function loadMap(sourceUrlList, bounds) {
    var tileGrid = new ol.tilegrid.TileGrid({
        extent: [bounds.left, bounds.bottom, bounds.right, bounds.top],
        resolutions: visualResolution
    });
    var view = new ol.View({
        center: [120, 30],
        minZoom: 0,
        zoom: zoomLevel,
        maxZoom: 12,
        projection: mapProjection,
        resolutions: visualResolution
    });
    var motherMapLayer = new ol.layer.Tile({
        title: "motherMap",
        source: new ol.source.TileSuperMapRest({
            url: sourceUrlList[0],
            tileGrid: tileGrid
        }),
        projection: mapProjection
    });
    var baseChartLayer = new ol.layer.Tile({
        title: "baseChart",
        source: new ol.source.TileSuperMapRest({
            url: sourceUrlList[1],
            transparent: true,
            tileGrid: tileGrid
        }),
        projection: mapProjection
    });

    map = new ol.Map({
        target: 'map',
        view: view,
        controls: ol.control.defaults({attributionOptions: {collapsed: true}})
    });
    map.addLayer(motherMapLayer);
    map.addLayer(baseChartLayer);

    //加载比例尺控件
    var scaleControl = new ol.control.ScaleLine();
    map.addControl(scaleControl);
    initFunctionalBtn();
    return map;
}

//测距 清除等操作
function initFunctionalBtn() {
    var buttons = $('.btn-group').children();
    buttons.map(function (key) {
        var value = buttons[key].value;
        if (value === 'Mock') {
            //模拟点位更新
            $(buttons[key]).on('click', function () {
                updateBoatFeature({lng: 120, lat: 30, code: '00', angle: 30});
            });
            return;
        }
        if (value === 'Measure') {
            //测距
            $(buttons[key]).on('click', function () {
                addInteraction();
            });
            return;
        }
        if (value === 'Clear') {
            //清除测距
            $(buttons[key]).on('click', function () {
                clearInteraction();
            });
            return;
        }
        if (value === 'SeeMap') {
            //切换海图的可见性
            $(buttons[key]).on('click', function () {
                if ($(buttons[key]).hasClass("see-map-show")) {
                    $(buttons[key]).removeClass("see-map-show")
                } else {
                    $(buttons[key]).addClass("see-map-show")
                }
                //遍历所有海图图层，更改其可见性
                map.getLayers().getArray().forEach(function (layer) {
                    if (layer.get('title') === "baseChart") {
                        layer.setVisible(!layer.getVisible());
                    }
                });
            });
            return;
        }
    });
}

function addInteraction() {
    measureSource = new ol.source.Vector();
    var vector = new ol.layer.Vector({
        source: measureSource,
        style: function (feature) {
            return styleFunction(feature, false);
        }
    });
    map.addLayer(vector);
    measureDraw = new ol.interaction.Draw({
        source: measureSource,
        type: 'LineString',
        style: function (feature) {
            return styleFunction(feature, false, 'LineString');
        }
    });
    map.addInteraction(measureDraw);
}

function clearInteraction() {
    if (measureDraw) {
        measureSource.clear();
        map.removeInteraction(measureDraw);
        measureDraw = null;
    }
}

function styleFunction(feature, segments, drawType) {
    const styles = [];
    const geometry = feature.getGeometry();
    const type = geometry.getType();
    let point, label, line;

    const style = new ol.style.Style({
        fill: new ol.style.Fill({
            color: 'rgba(255, 255, 255, 0.2)',
        }),
        stroke: new ol.style.Stroke({
            color: 'rgba(0, 0, 0, 0.5)',
            lineDash: [10, 10],
            width: 2,
        }),
        image: new ol.style.Circle({
            radius: 5,
            stroke: new ol.style.Stroke({
                color: 'rgba(0, 0, 0, 0.7)',
            }),
            fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 0.2)',
            }),
        }),
    });

    const labelStyle = new ol.style.Style({
        text: new ol.style.Text({
            font: '14px Calibri,sans-serif',
            fill: new ol.style.Fill({
                color: 'rgba(255, 255, 255, 1)',
            }),
            backgroundFill: new ol.style.Fill({
                color: 'rgba(0, 0, 0, 0.7)',
            }),
            padding: [3, 3, 3, 3],
            textBaseline: 'bottom',
            offsetY: -15,
        }),
        image: new ol.style.RegularShape({
            radius: 8,
            points: 3,
            angle: Math.PI,
            displacement: [0, 10],
            fill: new ol.style.Fill({
                color: 'rgba(0, 0, 0, 0.7)',
            }),
        }),
    });

    if (!drawType || drawType === type || type === 'Point') {
        styles.push(style);
        if (type === 'Polygon') {
            point = geometry.getInteriorPoint();
            label = formatArea(geometry);
            line = new ol.geom.LineString(geometry.getCoordinates()[0]);
        } else if (type === 'LineString') {
            point = new ol.geom.Point(geometry.getLastCoordinate());
            label = formatLength(geometry);
            line = geometry;
        }
    }
    if (segments && line) {
        const segmentStyle = new ol.style.Style({
            text: new ol.style.Text({
                font: '12px Calibri,sans-serif',
                fill: new ol.style.Fill({
                    color: 'rgba(255, 255, 255, 1)',
                }),
                backgroundFill: new ol.style.Fill({
                    color: 'rgba(0, 0, 0, 0.4)',
                }),
                padding: [2, 2, 2, 2],
                textBaseline: 'bottom',
                offsetY: -12,
            }),
            image: new ol.style.RegularShape({
                radius: 6,
                points: 3,
                angle: Math.PI,
                displacement: [0, 8],
                fill: new ol.style.Fill({
                    color: 'rgba(0, 0, 0, 0.4)',
                }),
            }),
        });
        const segmentStyles = [segmentStyle];

        let count = 0;
        line.forEachSegment(function (a, b) {
            const segment = new ol.geom.LineString([a, b]);
            const label = formatLength(segment);
            if (segmentStyles.length - 1 < count) {
                segmentStyles.push(segmentStyle.clone());
            }
            const segmentPoint = new ol.geom.Point(segment.getCoordinateAt(0.5));
            segmentStyles[count].setGeometry(segmentPoint);
            segmentStyles[count].getText().setText(label);
            styles.push(segmentStyles[count]);
            count++;
        });
    }
    if (label) {
        labelStyle.setGeometry(point);
        labelStyle.getText().setText(label);
        styles.push(labelStyle);
    }
    return styles;
}

const formatArea = function (polygon) {
    const area = ol.sphere.getArea(polygon, {"projection": "EPSG:4326"});
    let output;
    if (area > 10000) {
        output = Math.round((area / 1000000) * 100) / 100 + ' km\xB2';
    } else {
        output = Math.round(area * 100) / 100 + ' m\xB2';
    }
    return output;
};

const formatLength = function (line) {
    const length = ol.sphere.getLength(line, {"projection": "EPSG:4326"});
    let output;
    if (length > 100) {
        output = Math.round((length / 1000) * 100) / 100 + ' km';
    } else {
        output = Math.round(length * 100) / 100 + ' m';
    }
    return output;
};

/**
 * 需要实现
 * 绘制marker 或 更新marker
 * 没有的时候 绘制 存在了 就更新
 * @param boatStatus boat状态
 */
function drawOrUpdateMarker(boatStatus) {
    boatPointSource.getFeatures().forEach(function (f){
        if(f.getProperties().code == boatStatus.code){
            boatPointSource.removeFeature(f)
        }
        if(selectedBoatFeature.getProperties().code == boatStatus.code){
            boatPointSource.addFeature(createOneBoatFeatureByStatus(boatStatus,true));
            hideBoatInfo();
        }else{
            boatPointSource.addFeature(createOneBoatFeatureByStatus(boatStatus))
        }
    })
}

/**
 * 地图动画移动至boat
 * @param code
 */
function mapPanTo(code) {
    let boat = getBoatByCode(code)
    if (boat.statusList[0] == null) return;
    let lng = boat.statusList[0].lng;
    let lat = boat.statusList[0].lat;
    mapPanByLocationWithZoomChange(lng, lat)
}

/**
 * 需要实现
 * 地图动画移动至经纬度点,zoom <= boatIconChangedZoom 就更改为 boatIconChangedZoom +1 否则不变
 * @param lng
 * @param lat
 */
function mapPanByLocationWithZoomChange(lng, lat) {
    var panZoom = boatIconChangedZoom + 1;
    if (zoomLevel > boatIconChangedZoom) {
        panZoom = zoomLevel;
    }
    map.getView().animate({
        center: [lng, lat],
        zoom: panZoom,
        duration: 200
    });
}

function mapPanByLocationWithoutZoomChange(lng, lat) {
    map.getView().animate({
        center: [lng, lat],
        zoom: zoomLevel,
        duration: 200
    });
}

/**
 * 需要调用
 * 地图marker鼠标移入
 * @param code 艇编号
 * @param top 距离窗口上方的像素点
 * @param left 距离窗口左边的像素点
 */
function mapMarkHoverIn(code, top, left) {
    let boat = getBoatByCode(code)
    showBoatInfo(boat, top, left)
}

/**
 * 需要调用
 * 地图marker鼠标移出
 */
function mapMarkHoverOut() {
    hideBoatInfo()
}

/**
 * 需要调用
 * marker 点击
 * @param code 艇编号
 */
function mapMarkerClick(code) {
    showRightDiv(code)
    mapPanTo(code) // 填入艇位置
}

/**
 * 需要调用
 * 地图移动时调用该函数
 */
function mapMoved() {
    hideBoatInfo();
}
